/**
 * Created By xiyuan
 * Author server@xiyuan.name (惜缘叛逆)
 * DateTime 2019/3/11 5:50 PM
 * Describe javascript功能描述
 * MIT License http://www.opensource.org/licenses/mit-license.php
 */

// 路径包
const path = require('path');
// 子进程
const {spawn} = require('child_process');
// 计算机类型
const platform = require('os').platform();
// 日志解析
const logParse = require('./logParse');
// 工具
const {createLog} = require('./utils');

// 配置目录
const configDir = path.join(__dirname, '/../config/');
// bin路径
const binDir = path.join(__dirname, '/../bin');
// 客户端bin指令
const client_bin = './frpc' + (platform === 'win32' ? '.exe' : '');
// 服务端bin指令
const server_bin = './frps' + (platform === 'win32' ? '.exe' : '');


// 进程容器
const processContainer = {
	server: {},
	client: {},
};


// 指令启动目录
let dir = binDir;

// 进程类
class Process {
	constructor(binType, target) {
		// 标记是否启动成功
		this.isStart = false;
		// 进程类型
		this.binType = binType;
		// 进程名称
		this.name = target.name;
		// 进程日志
		this.logPath = target.logPath;
		// 关联记录进程
		processContainer[binType][target.name] = this;
		// 事件记录器
		this.eventMap = {
			start: [],
			info: [],
			error: [],
			close: [],
		};
	}
	
	// 启动进程
	start() {
		if (this.spawn) return console.log('进程已存在～')
		// 执行指令脚本
		let bin = {
			client_bin,
			server_bin
		}[this.binType + '_bin'];
		// 目标进程名称
		const tagterName = this.name;
		// 对应的配置路径
		const configPath = path.normalize(configDir + this.binType + '/' + tagterName + '.ini')
		// 进程参数
		const args = ['-c', configPath];
		
		// 监听日志文件
		logParse(this.logPath)
			.watchWarn(info => {
				this.eventMap.error.forEach(fn => fn(info));
			})
			.watchInfo(info => {
				// 用于处理服务启动事件
				if (!this.isStart) {
					this.isStart = true;
					this.eventMap.start.forEach(fn => fn(this));
				}
				this.eventMap.info.forEach(fn => fn(info));
			})
			.watchError(info => {
				this.eventMap.error.forEach(fn => fn(info));
			})
		
		// 启动子进程
		this.spawn = spawn(bin, args, {cwd: dir, detached: false});
		
		// 监听输出
		this.spawn.stdout.on('data', data => {
			this.eventMap.error.forEach(fn => fn(createLog(new Error(data.toString()))))
		});
		
		// 监听错误输出
		this.spawn.stderr.on('data', data => {
			this.eventMap.error.forEach(fn => fn(createLog(new Error(data.toString()))))
		});
		
		// 监听进程关闭
		this.spawn.on('exit', () => {
			this.eventMap.close.forEach(fn => fn(createLog(new Error('进程退出'))))
		});
		
		/*if (!this.isStart) {
			this.isStart = true;
			this.eventMap.start.forEach(fn => fn(this));
		}*/
		return this;
	}
	
	// 停止进程
	stop() {
		// 进程销毁
		this.spawn.kill();
		// 事件移除
		this.spawn.stdout.removeAllListeners('data');
		this.spawn.stderr.removeAllListeners('data');
		delete this.spawn;
		return this;
	}
	
	destroy() {
		if (this.spawn) this.stop();
		delete processContainer[this.binType][this.name];
	}
	
	watchStart(fn) {
		// 事件记录
		this.eventMap.start.push(fn);
		return this;
	}
	
	// 监听信息输出
	watchInfo(fn) {
		// 事件记录
		this.eventMap.info.push(fn);
		return this;
	}
	
	// 监听错误输出
	watchError(fn) {
		// 事件记录
		this.eventMap.error.push(fn);
		return this;
	}
	
	// 监听进程关闭
	watchClose(fn) {
		// 事件记录
		this.eventMap.close.push(fn);
		return this;
	}
}

module.exports = {
	// 进程容器
	processContainer,
	// 创建进程
	createProcess(binType, target) {
		return new Process(binType, target)
	},
	getProcess(binType, targetName) {
		return processContainer[binType][typeof targetName === 'object' ? targetName.name : targetName]
	},
};

